import React from 'react';
import ReactDOM from 'react-dom';
import * as turf from '@turf/turf';
import mapboxgl from 'mapbox-gl';
import PopupCom from 'src/components/PopupCom';
import mapMarker from '@/images/map-marker.png';
import mapActiveMarker from '@/images/map-active-marker.png';
// 自定义元素事件
export const customElEvent = (el, lngLat, { cmCallback, dbCallback, cCallback, mlCallback, meCallback } = {}) => {
  // 鼠标进入事件
  el.addEventListener('mouseenter', (markerEvent) => {
    markerEvent.stopPropagation();
    markerEvent.preventDefault();
    meCallback && meCallback(el, lngLat);
  });
  // 鼠标离开事件
  el.addEventListener('mouseleave', (markerEvent) => {
    markerEvent.stopPropagation();
    markerEvent.preventDefault();
    mlCallback && mlCallback(el, lngLat);
  });
  // 点位单击事件
  el.addEventListener('click', (markerEvent) => {
    markerEvent.stopPropagation();
    markerEvent.preventDefault();
    cCallback && cCallback(el, lngLat);
  });
  // 点位双击事件
  el.addEventListener('dblclick', (markerEvent) => {
    markerEvent.stopPropagation();
    markerEvent.preventDefault();
    dbCallback && dbCallback(el, lngLat);
  });
  // 点位右键事件
  el.addEventListener('contextmenu', (markerEvent) => {
    markerEvent.stopPropagation();
    markerEvent.preventDefault();
    cmCallback && cmCallback(el, lngLat);
  });
};

/**
 * 打开弹框页面
 * @param {*} event
 * @param {*} el
 */
export const openMarkerCom = (event, el) => {
  ReactDOM.render(<PopupCom {...event}></PopupCom>, el);
};

/**
 * 从后端获取结果后，转化为点位geojson
 * @param {*} result
 */
export const getGeojsonPointDataSource = (result = []) => {
  const pointGeojson = {
    type: 'FeatureCollection',
    features: [],
  };
  if (result.length > 0) {
    result.forEach((item) => {
      const feature = {
        type: 'Feature',
        properties: {
          ...item,
        },
        geometry: {},
      };
      feature.geometry = {
        type: 'Point',
        coordinates: [item?.lng, item?.lat],
      };
      pointGeojson.features.push(feature);
    });
  }
  return pointGeojson;
};

/**
 * 添加静态图标
 */
export const addStaticImg = (justMap, id, { defalutIcon, highlighIcon }) => {
  if (justMap) {
    const imageLilst = [
      { name: `mapMarker_${id}`, icon: defalutIcon || mapMarker },
      { name: `mapActiveMarker_${id}`, icon: highlighIcon || mapActiveMarker },
    ];
    imageLilst.forEach((img) => {
      if (!justMap.hasImage(img.name)) {
        justMap.loadImage(img.icon, (err, image) => {
          if (err) throw err;
          justMap.addImage(img.name, image);
        });
      }
    });
  }
};
/**
 * 更新静态图标
 * @param {*} justMap
 * @param {*} name
 * @param {*} img
 */
export const updateStaticImg = (justMap, name, img) => {
  justMap.removeImage(name);
  justMap.loadImage(img, (err, image) => {
    if (err) throw err;
    justMap.map.addImage(name, image);
  });
};

/**
 * 散点图层渲染
 * @param {*} justMap
 */
export const addScatterBLayer = ({ justMap, activeId, geoJsonData }) => {
  if (!justMap) return false;
  const sourceId = 'scatterSource';
  const layerId = 'scatterLayer';
  if (justMap.getSource(sourceId)) {
    justMap.getSource(sourceId).setData(null);
  } else {
    geoJsonData &&
      justMap.addSource(sourceId, {
        type: 'geojson',
        data: geoJsonData,
      });
  }
  justMap.addLayer({
    id: layerId,
    source: sourceId,
    type: 'symbol',
    layout: {
      'icon-image': ['case', ['==', ['get', 'id'], activeId], 'mapMarker', 'mapActiveMarker'],
      'icon-size': 0.5,
      'text-anchor': 'top',
      'text-size': 12,
      'icon-offset': [0, -15],
      'text-offset': [0, -2.5],
    },
    paint: {
      'text-halo-color': 'rgba(248,232,232,1)',
      'text-halo-width': 2,
    },
  });
  justMap.on('mouseenter', layerId, () => {
    justMap.getCanvas().style.cursor = 'pointer';
  });
  justMap.on('mouseleave', layerId, () => {
    justMap.getCanvas().style.cursor = '';
  });
  justMap.on('click', layerId, (e) => {
    const featureItem = e.features[0];
    if (featureItem) {
      justMap.setLayerProperty(layerId, {
        layout: {
          'icon-size': ['case', ['==', ['get', 'id'], featureItem.properties?.id], 0.8, 0.5],
        },
      });
    }
  });
};

/**
 * 定位到选中feature
 * @param featureItem
 */
export const flyToFeature = (justMap, featureCollection) => {
  if (!justMap) return false;
  if (featureCollection.features.length > 0) {
    const viewPortBbox = turf.bbox(featureCollection);
    justMap.fitBounds(
      [
        [viewPortBbox[0], viewPortBbox[1]],
        [viewPortBbox[2], viewPortBbox[3]],
      ],
      { padding: { top: 150, bottom: 150, left: 250, right: 50 } }
    );
  }
};

/**
 * 点位重点显示
 * @param {*} justMap
 * @param {*} layerId
 * @param {*} dataId
 * @param {*} iconSize
 */
export const pointWeight = (justMap, layerId, dataId, iconSize) => {
  const mapLayers = justMap.getLayers();
  if (mapLayers && mapLayers.length) {
    mapLayers.forEach((f) => {
      if (/^scatter_(\w)*$/.test(f.id)) {
        justMap.setLayerProperty(f.id, {
          layout: {
            unClusterIconSize: iconSize,
          },
        });
      }
    });
  }

  dataId &&
    justMap.setLayerProperty(layerId, {
      layout: {
        unClusterIconSize: ['case', ['==', ['get', 'id'], dataId], iconSize + 0.1, iconSize],
      },
    });
};

/**
 * 在地图中增加菜单点位
 * @param {*} justMap
 * @param {*} event
 * @param {*} param
 */
export const appPopup = (justMap, event, { id, className, offset = [0, 0, 0], cmCallback, dbCallback, cCallback, doneCallback }) => {
  const { lngLat } = event;
  if (justMap && justMap.map) {
    const esScatterDom = document.getElementById(id);
    if (esScatterDom) {
      esScatterDom.remove();
    }
    const el = document.createElement('div');
    id && (el.id = id);
    className && (el.className = className);
    customElEvent(el, lngLat, { cmCallback, dbCallback, cCallback });
    const popupObj = new mapboxgl.Popup({
      closeButton: false,
      closeOnClick: false,
      offset,
    })
      .setLngLat([lngLat.lng, lngLat.lat])
      .setDOMContent(el)
      .addTo(justMap.map);
    // 点位增加完毕回调事件
    setTimeout(() => {
      doneCallback && doneCallback(el, lngLat, popupObj);
    }, 100);
  }
};

/**
 *  删除点位浮窗
 * @param {*} id
 */
export const removePopupById = (id) => {
  const esScatterDom = document.getElementById(id);
  if (esScatterDom) {
    esScatterDom.remove();
  }
};

/**
 * 图层置顶
 * @param {*} justMap
 * @param {*} istopId
 */
export const layerIstop = (justMap, istopId) => {
  if (!justMap) return false;
  const moveLayerIds = justMap.map
    .getStyle()
    .layers.filter((f) => /scatter_(\d)*-unClusterIcon/.test(f.id))
    .map((m) => m.id)
    .filter((f) => !f.includes(istopId));
  if (moveLayerIds && moveLayerIds.length !== 0) {
    moveLayerIds.forEach((f) => {
      justMap.map.moveLayer(f, istopId);
    });
  }
};

// 根据圈选范围，增加范围边界
export const addLineLayer = (justMap) => {
  const sourceId = 'draw_scope';
  const layerId = 'draw_scope_layer';
  return {
    create: (feature, { drawColor, drawOpacity, drawWidth, drawLineType }) => {
      justMap.addSource(sourceId, {
        type: 'geojson',
        data: feature,
      });
      const layerOption = {
        id: layerId,
        type: 'line',
        source: sourceId,
        layout: {
          'line-join': 'round',
          'line-cap': 'round',
        },
        paint: {
          'line-color': drawColor,
          'line-opacity': drawOpacity,
          'line-width': drawWidth,
        },
      };
      if (drawLineType === 'dashed') {
        layerOption.paint['line-dasharray'] = [2, 4];
      }
      justMap.addLayer(layerOption);
    },
    remove: () => {
      const isLayer = justMap.getLayer(layerId);
      const isSource = justMap.getSource(sourceId);
      isLayer && justMap.removeLayer(layerId);
      isSource && justMap.removeSource(sourceId);
    },
  };
};

/**
 * 地图工厂函数
 */
export default (justMap) => ({
  addStaticImg: (...args) => addStaticImg(justMap, ...args),
  addScatterBLayer: (...args) => addScatterBLayer(Object.assign(args[0], { justMap })),
  flyToFeature: (...args) => flyToFeature(justMap, ...args),
  pointWeight: (...args) => pointWeight(justMap, ...args),
  appPopup: (...args) => appPopup(justMap, ...args),
  updateStaticImg: (...args) => updateStaticImg(justMap, ...args),
  addLineLayer: (...args) => addLineLayer(justMap, ...args),
  layerIstop: (...args) => layerIstop(justMap, ...args),
});
